package com.pig4cloud.pigx.wallet.websocket.subscribe;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.customize.utils.CommonUtil;
import com.pig4cloud.pigx.common.websocket.holder.SessionKeyGenerator;
import com.pig4cloud.pigx.contract.api.feign.ContractPositionFeign;
import com.pig4cloud.pigx.wallet.entity.CapitalAccount;
import com.pig4cloud.pigx.wallet.entity.ContractAccount;
import com.pig4cloud.pigx.wallet.service.CapitalAccountService;
import com.pig4cloud.pigx.wallet.service.ContractAccountService;
import com.pig4cloud.pigx.wallet.vo.AbstractTopicVO;
import com.pig4cloud.pigx.wallet.websocket.AssetListVo;
import com.pig4cloud.pigx.wallet.websocket.CapitalAccountVo;
import com.pig4cloud.pigx.wallet.websocket.ContractAccountVo;
import com.pig4cloud.pigx.wallet.websocket.TotalAssetsVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketSession;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 */
@Slf4j
@Component
public class MergeWallet extends DataListAbstractTopic {
	private final ContractAccountService contractAccountService;

	private final CapitalAccountService capitalAccountService;

	private final SessionKeyGenerator sessionKeyGenerator;

	private final ContractPositionFeign feign;


	protected String TOPICNAME = "mergeWallet";

	public MergeWallet(ContractAccountService contractAccountService, CapitalAccountService capitalAccountService, SessionKeyGenerator sessionKeyGenerator, ContractPositionFeign feign, CommonUtil commonUtil) {
		this.contractAccountService = contractAccountService;
		this.capitalAccountService = capitalAccountService;
		this.sessionKeyGenerator = sessionKeyGenerator;
		this.feign = feign;
		init();
	}

	private void init() {
		wsPush();
	}

	private void wsPush() {
		ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
		service.scheduleAtFixedRate(() -> {
			try {
				for (Map.Entry<WebSocketSession, AbstractTopicVO> entry : subList.entrySet()) {
					sendMessage(entry);
				}
			} catch (Exception e) {
				e.printStackTrace();
				log.info("push ranking err:" + e.getMessage());
			}

		}, 0, 2000, TimeUnit.MILLISECONDS);
	}

	public void sendMessage(Map.Entry<WebSocketSession, AbstractTopicVO> entry) {
		if (!entry.getKey().isOpen()) {
			return;
		}
		try {
			Object userId = sessionKeyGenerator.sessionKey(entry.getKey());
			ContractAccountVo contractAccount = getContractAccount(userId);
			CapitalAccountVo capitalAccount = getCapitalAccount(userId);
			TotalAssetsVo totalAssets = getTotalAssets(userId);
			totalAssets.setContractAccount(contractAccount.getTotal().toPlainString());
			totalAssets.setTotalAssets(new BigDecimal(capitalAccount.getTotalAssets()).add(contractAccount.getTotal()).toPlainString());
			JSONObject object = new JSONObject();
			object.put("contractAccount", contractAccount);
			object.put("capitalAccount", capitalAccount);
			object.put("totalAssets", totalAssets);
			// 发送消息
			entry.getKey().sendMessage(getTextMessage(entry.getValue().getDataList(), object));
		} catch (Exception ex) {
			ex.printStackTrace();
			log.info("push last price err:" + ex.getMessage());
		}
	}

	private ContractAccountVo getContractAccount(Object userId) {
		ContractAccountVo contractAccountVo = new ContractAccountVo();
		ContractAccount contractAccount = contractAccountService.getOne(new LambdaQueryWrapper<ContractAccount>()
				.eq(ContractAccount::getUserId, userId));

		// 查询未实现盈亏，精度2
		R<BigDecimal> floatProfitR = feign.getFloatProfitByUser(Long.valueOf(userId.toString()), SecurityConstants.FROM_IN);
		BigDecimal floatProfit = floatProfitR.getIsSuccess() ? floatProfitR.getData() : BigDecimal.ZERO;

		try {
			// 精度4
			int scale = 4;
			// 向下取值
			RoundingMode mode = RoundingMode.DOWN;

			// 转换为BigDecimal，并设置精度，向下取值
			BigDecimal total = contractAccount.getMarginBalance().setScale(scale, mode);
			BigDecimal available = contractAccount.getWalletBalance().setScale(scale, mode);
			BigDecimal frozen = contractAccount.getFrozen().setScale(scale, mode);
			BigDecimal positionMargin = contractAccount.getPositionMargin().setScale(scale, mode);


			// 可用额度
			contractAccountVo.setAvailable(available);
			// 冻结额度
			contractAccountVo.setFrozen(frozen);
			// （持仓保证金）占用额度
			contractAccountVo.setPositionMargin(positionMargin);
			// 未实现盈亏
			contractAccountVo.setFloatProfit(floatProfit);
			// 总资产
			contractAccountVo.setTotal(
					contractAccountVo.getAvailable()
							.add(contractAccountVo.getFrozen())
							.add(contractAccountVo.getFloatProfit())
							.add(contractAccountVo.getPositionMargin())
			);

		} catch (Exception e) {
			contractAccountVo.setTotal(BigDecimal.ZERO);
			contractAccountVo.setAvailable(BigDecimal.ZERO);
			contractAccountVo.setFrozen(BigDecimal.ZERO);
			contractAccountVo.setPositionMargin(BigDecimal.ZERO);
			contractAccountVo.setFloatProfit(BigDecimal.ZERO);
		}
		return contractAccountVo;
	}

	private CapitalAccountVo getCapitalAccount(Object userId) {
		CapitalAccountVo capitalAccountVo = new CapitalAccountVo();
		AssetListVo assetListVo = new AssetListVo();
		List<AssetListVo> list = new ArrayList<>();

		CapitalAccount capitalAccount = capitalAccountService.getOne(new LambdaQueryWrapper<CapitalAccount>()
				.eq(CapitalAccount::getUserId, userId)
		);

		assetListVo.setCurrency("1");
		// 精度控制 4 位
		assetListVo.setAvailable(capitalAccount.getAvailable().setScale(4, RoundingMode.DOWN).toPlainString());
		assetListVo.setFrozen(capitalAccount.getFrozen().setScale(4, RoundingMode.DOWN).toPlainString());
		BigDecimal total = capitalAccount.getAvailable().add(capitalAccount.getFrozen()).setScale(4, RoundingMode.DOWN);
		assetListVo.setTotal(total.toPlainString());
		list.add(assetListVo);

		capitalAccountVo.setAssetList(list);
		capitalAccountVo.setTotalAssets(assetListVo.getTotal());
		return capitalAccountVo;
	}

	private TotalAssetsVo getTotalAssets(Object userId) {
		TotalAssetsVo totalAssetsVo = new TotalAssetsVo();

		CapitalAccount capitalAccount = capitalAccountService.getOne(new LambdaQueryWrapper<CapitalAccount>()
				.eq(CapitalAccount::getUserId, userId)
		);

		ContractAccount contractAccount = contractAccountService.getOne(new LambdaQueryWrapper<ContractAccount>()
				.eq(ContractAccount::getUserId, userId)
		);
		// 精度控制4位
		totalAssetsVo.setCapitalAccount(capitalAccount.getAvailable().setScale(4, RoundingMode.DOWN).toPlainString());
		totalAssetsVo.setContractAccount(contractAccount.getMarginBalance().setScale(4, RoundingMode.DOWN).toPlainString());
		BigDecimal capitalFrozen = capitalAccount.getFrozen().setScale(4, RoundingMode.DOWN);
		BigDecimal total = capitalAccount.getAvailable().add(capitalFrozen)
				.add(contractAccount.getMarginBalance())
				.setScale(4, RoundingMode.DOWN);
		totalAssetsVo.setTotalAssets(total.toPlainString());
		return totalAssetsVo;
	}
}
